﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;

namespace XNET.WEB
{
    /// <summary>
    /// 快盘存储API
    /// </summary>
    public class XKuaiPan
    {
        private string xAccessTokenUrl = "https://openapi.kuaipan.cn/open/xAccessToken";
        private string requestTokenUrl = "https://openapi.kuaipan.cn/open/requestToken";
        private string accessTokenUrl = "https://openapi.kuaipan.cn/open/accessToken";
        private string account_infoUrl = "http://openapi.kuaipan.cn/1/account_info/";
        private string metadataUrl = "http://openapi.kuaipan.cn/1/metadata/app_folder/";

        #region 类成员
        private string _http_method = "GET";
        /// <summary>
        /// 请求方式
        /// </summary>
        public string http_method
        {
            get
            {
                return _http_method;
            }
            set
            {
                _http_method = value;
            }
        }

        private string _oauth_version = "1.0";
        /// <summary>
        /// 版本
        /// </summary>
        public string oauth_version
        {
            get
            {
                return _oauth_version;
            }
            set
            {
                _oauth_version = value;
            }
        }

        private string _oauth_signature_method = "HMAC-SHA1";
        /// <summary>
        /// 签名
        /// </summary>
        public string oauth_signature_method
        {
            get
            {
                return _oauth_signature_method;
            }
            set
            {
                _oauth_signature_method = value;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string BaseUri
        {
            get;
            set;
        }
        /// <summary>
        ///验证码，用于 accessToken
        /// </summary>
        private string _oauth_verifier;
        /// <summary>
        /// consumer_key
        /// </summary>
        public string oauth_consumer_key { set; get; }
        /// <summary>
        /// consumer_secret
        /// </summary>
        public string consumer_secret { get; set; }
        /// <summary>
        ///未授权的token
        /// </summary>
        public string oauth_token { get; set; }
        /// <summary>
        /// 对应secret
        /// </summary>
        public string oauth_token_secret { get; set; }

        private string x_auth_username;
        private string x_auth_password;
        #endregion

        /// <summary>
        /// 
        /// </summary>
        public XKuaiPan()
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="oauth_consumer_key"></param>
        /// <param name="consumer_secret"></param>
        public XKuaiPan(string oauth_consumer_key, string consumer_secret)
        {
            this.oauth_consumer_key = oauth_consumer_key;
            this.consumer_secret = consumer_secret;
        }

        #region URL
        /// <summary>
        /// 第一步:获取请求的URL
        /// </summary>
        /// <returns></returns>
        private string GetRequestTokenUrl()
        {
            SortedDictionary<string, string> ParamList = new SortedDictionary<string, string>();
            ParamList.Add("oauth_consumer_key", this.oauth_consumer_key);
            ParamList.Add("oauth_nonce", GetRandomString(8));
            ParamList.Add("oauth_timestamp", GetTimeStamp());
            ParamList.Add("oauth_version", this.oauth_version);
            ParamList.Add("oauth_signature_method", this.oauth_signature_method);
            string SourceString = GetApiSourceString(this.requestTokenUrl, ParamList);
            string SecretKey = GetSecretKey(this.consumer_secret, "");
            string Sign = GetSignature(SourceString, SecretKey);
            ParamList.Add("oauth_signature", Sign);
            string url = this.requestTokenUrl + "?" + ParamToUrl(ParamList, false);
            return url;
        }
        /// <summary>
        /// 验证授权
        /// </summary>
        /// <returns></returns>
        private string GetxAccessTokenUrl()
        {
            SortedDictionary<string, string> ParamList = new SortedDictionary<string, string>();
            ParamList.Add("x_auth_mode", "client_auth");
            ParamList.Add("x_auth_username", x_auth_username);
            ParamList.Add("x_auth_password", x_auth_password);

            return BuildUrl(xAccessTokenUrl, this.oauth_token, this.oauth_token_secret, ParamList);
        }

        /// <summary>
        /// 第三步:用临时的token ,secret获取真正的token
        /// </summary>
        /// <param name="oauth_token"></param>
        /// <param name="oauth_token_secret"></param>
        /// <returns></returns>
        private string GetAccessTokenUrl(string oauth_token, string oauth_token_secret)
        {
            return BuildUrl(this.accessTokenUrl, oauth_token, oauth_token_secret);
        }
        /// <summary>
        /// 获取帐号信息对应的URL
        /// </summary>
        /// <param name="oauth_token"></param>
        /// <param name="oauth_token_secret"></param>
        /// <returns></returns>
        private string GetAccount_InfoUrl(string oauth_token, string oauth_token_secret)
        {
            return BuildUrl(this.account_infoUrl, oauth_token, oauth_token_secret);
        }

        /// <summary>
        /// 获取文件夹信息
        /// </summary>
        /// <param name="oauth_token"></param>
        /// <param name="oauth_token_secret"></param>
        /// <returns></returns>
        public string GetMetadataUrl(string oauth_token, string oauth_token_secret)
        {
            return BuildUrl(this.metadataUrl, oauth_token, oauth_token_secret);
        }
        /// <summary>
        /// 返回是一个 web 页面，要求快盘用户登陆和授权。
        /// </summary>
        /// <returns></returns>
        public string GetAuthorizeUrl()
        {
            return string.Format("https://www.kuaipan.cn/api.php?ac=open&op=authorise&oauth_token={0}", oauth_token);
        }
        #endregion

        #region 辅助函数
        /// <summary>
        /// 根据API地址和授权类型生成URL
        /// </summary>
        /// <param name="Url"></param>
        /// <param name="oauth_token"></param>
        /// <param name="oauth_token_secret"></param>
        /// <returns></returns>
        private string BuildUrl(string Url, string oauth_token, string oauth_token_secret)
        {
            return BuildUrl(Url, oauth_token, oauth_token_secret, null);
        }
        /// <summary>
        /// 根据API地址和授权类型生成URL
        /// </summary>
        /// <param name="Url"></param>
        /// <param name="oauth_token"></param>
        /// <param name="oauth_token_secret"></param>
        ///  <param name="urlParams"></param>
        /// <returns></returns>
        private string BuildUrl(string Url, string oauth_token, string oauth_token_secret,SortedDictionary<string,string> urlParams)
        {
            SortedDictionary<string, string> ParamList = new SortedDictionary<string, string>();
            ParamList.Add("oauth_consumer_key", this.oauth_consumer_key);
            ParamList.Add("oauth_nonce", GetRandomString(20));
            ParamList.Add("oauth_timestamp", GetTimeStamp());
            ParamList.Add("oauth_version", this.oauth_version);
            ParamList.Add("oauth_signature_method", this.oauth_signature_method);
            if(!string.IsNullOrEmpty(oauth_token)) ParamList.Add("oauth_token", oauth_token);
            if (urlParams != null && urlParams.Count > 0)
            {
                foreach (KeyValuePair<string, string> urlParam in urlParams)
                {
                    ParamList.Add(urlParam.Key, urlParam.Value);
                }
            }
            string SourceString = GetApiSourceString(Url, ParamList);
            string SecretKey = GetSecretKey(this.consumer_secret, oauth_token_secret);
            string Sign = GetSignature(SourceString, SecretKey);
            ParamList.Add("oauth_signature", Sign);
            if (!string.IsNullOrEmpty(this._oauth_verifier)) ParamList.Add("oauth_verifier", this._oauth_verifier);
            string url = Url + "?" + ParamToUrl(ParamList, false);
            return url;
        }

        /// <summary>
        /// 获取源串.
        /// </summary>
        /// <returns></returns>
        private string GetApiSourceString(string baseUrl, SortedDictionary<string, string> ParamList)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(http_method + "&");
            sb.Append(UrlEncode(baseUrl) + "&");
            string InnerParam = ParamToUrl(ParamList, true);

            sb.Append(UrlEncode(InnerParam));
            return sb.ToString();
        }

        /// <summary>
        /// 获取签名值.
        /// </summary>
        /// <param name="SourceString"></param>
        /// <param name="SecretKey"></param>
        /// <returns></returns>
        private string GetSignature(string SourceString, string SecretKey)
        {
            return UrlEncode(Hmac_Sha1AndBase64(SourceString, SecretKey));
        }

        /// <summary>
        /// 获取密钥
        /// </summary>
        /// <param name="consumer_secret"></param>
        /// <param name="oauth_token_secret"></param>
        /// <returns></returns>
        private string GetSecretKey(string consumer_secret, string oauth_token_secret)
        {
            return consumer_secret + "&" + oauth_token_secret;
        }


        private string ParamToUrl(SortedDictionary<string, string> dictParam, bool isEncode)
        {
            StringBuilder sb = new StringBuilder();
            foreach (KeyValuePair<string, string> key in dictParam)
            {
                if (isEncode)
                {
                    sb.AppendFormat("&{0}={1}", UrlEncode(key.Key), UrlEncode(key.Value));
                }
                else
                    sb.AppendFormat("&{0}={1}", key.Key, key.Value);
            }
            return sb.ToString().TrimStart('&');
        }

        private string UrlEncode(string str)
        {
            StringBuilder sb = new StringBuilder();
            byte[] byStr = System.Text.Encoding.UTF8.GetBytes(str); //默认是System.Text.Encoding.Default.GetBytes(str)
            for (int i = 0; i < byStr.Length; i++)
            {
                if ((byStr[i] >= 48 && byStr[i] <= 57)
                    || (byStr[i] >= 97 && byStr[i] <= 122)
                    || (byStr[i] >= 65 && byStr[i] <= 90)
                    || (byStr[i] == 46)
                || byStr[i] == 45
                    || byStr[i] == 95
                    || byStr[i] == 126
                   )
                {
                    sb.Append((char)byStr[i]);
                }
                else
                {
                    string t = Convert.ToString(byStr[i], 16);
                    sb.AppendFormat(@"%{0}", t.ToUpper());
                }
            }
            return sb.ToString();
        }

        private string Hmac_Sha1AndBase64(string Source, string SecretKey)
        {
            System.Security.Cryptography.HMACSHA1 hmacsha1 = new System.Security.Cryptography.HMACSHA1();
            hmacsha1.Key = System.Text.Encoding.ASCII.GetBytes(SecretKey);
            byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(Source); //signatureBase要进行签名的基础字符串
            byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
            return Convert.ToBase64String(hashBytes);
        }

        /// <summary>
        /// 获取时间戳
        /// </summary>
        /// <returns></returns>
        private string GetTimeStamp()
        {
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            DateTime dtNow = DateTime.Parse(DateTime.Now.ToString());
            TimeSpan toNow = dtNow.Subtract(dtStart);
            string timeStamp = toNow.Ticks.ToString();
            timeStamp = timeStamp.Substring(0, timeStamp.Length - 7);
            return timeStamp;
        }

        /// <summary>
        /// 获取随机字符串
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        private string GetRandomString(int length)
        {
            string result = System.Guid.NewGuid().ToString();
            result = result.Replace("-", "");
            return result.Substring(0, length);
        }
        #endregion

        #region 获取当前主机
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string GetCurrentFullHost()
        {
            HttpRequest request = System.Web.HttpContext.Current.Request;
            if (!request.Url.IsDefaultPort)
            {
                return string.Format("{0}:{1}", request.Url.Host, request.Url.Port.ToString());
            }
            return request.Url.Host;
        }
        #endregion

        #region 快盘操作
        /// <summary>
        /// 获取未授权的临时 token 快盘授权第一步
        /// </summary>
        public void GetRequestToken()
        {
            HttpItem item = new HttpItem();
            item.URL = GetRequestTokenUrl();

            XHttp http = new XHttp();
            HttpResult result = http.GetHtml(item);
            if (result.StatusCode == System.Net.HttpStatusCode.OK)
            {
                JObject obj = JObject.Parse(result.Html);
                oauth_token_secret = obj["oauth_token_secret"].ToString();
                oauth_token = obj["oauth_token"].ToString();
            }
        }
        /// <summary>
        /// 用户验证 token。这个接口返回是一个 web 页面，要求快盘用户登陆和授权。 快盘授权第二步
        /// </summary>
        public void GetAuthorize()
        {
            System.Diagnostics.Process.Start(GetAuthorizeUrl());
        }
        /// <summary>
        /// 用临时 token 换取 access token。 快盘授权第三步
        /// </summary>
        /// <param name="oauth_verifier">第二步授权返回的验证码</param>
        public void GetAccessToken(string oauth_verifier)
        {
            this._oauth_verifier = oauth_verifier;
            HttpItem item = new HttpItem();
            item.URL = GetAccessTokenUrl(oauth_token,oauth_token_secret);
            XHttp http = new XHttp();
            HttpResult result = http.GetHtml(item);
            if (result.StatusCode == System.Net.HttpStatusCode.OK)
            {
                JObject obj = JObject.Parse(result.Html);
                oauth_token_secret = obj["oauth_token_secret"].ToString();
                oauth_token = obj["oauth_token"].ToString();
            }
        }

        /// <summary>
        /// 验证授权是否通过
        /// </summary>
        /// <param name="kUserName">用户名</param>
        /// <param name="kUserPass">密码</param>
        public void GetxRequestToken(string kUserName, string kUserPass)
        {
            HttpItem item = new HttpItem();
            item.URL = GetxAccessTokenUrl();
            item.Encoding = Encoding.UTF8;

            x_auth_username = kUserName;
            x_auth_password = kUserPass;

            XHttp http = new XHttp();
            HttpResult result = http.GetHtml(item);
            if (result.StatusCode == System.Net.HttpStatusCode.OK)
            {
                JObject obj = JObject.Parse(result.Html);
                oauth_token_secret = obj["oauth_token_secret"].ToString();
                oauth_token = obj["oauth_token"].ToString();
            }
        }
        #endregion
    }
}
